﻿#pragma once

#include <learn/utils/singleton.h>

#include <functional>
#include <map>
#include <string>
#include <vector>

namespace xi
{

namespace utils
{

// 基类
class ReflectionObject;

// 构造指针
using create_object = ReflectionObject *(*)();

namespace details
{

class ReflectionField
{
  public:
    ReflectionField(ReflectionField &&) = delete;

    /**
     * @brief 默认构造
     *
     */
    ReflectionField() = default;

    /**
     * @brief 标准构造
     *
     * @param[in] name
     * @param[in] type
     * @param[in] offset
     */
    ReflectionField(const std::string &name, const std::string &type, size_t offset)
        : m_name(name), m_type(type), m_offset(offset)
    {
    }

    /**
     * @brief 字段名
     *
     * @return const std::string&
     */
    const std::string &name() const noexcept
    {
        return m_name;
    }

    /**
     * @brief 字段类型
     *
     * @return const std::string&
     */
    const std::string &type() const noexcept
    {
        return m_type;
    }

    /**
     * @brief 偏移量
     *
     * @return std::size_t
     */
    std::size_t offset() const noexcept
    {
        return m_offset;
    }

  private:
    std::string m_name;
    std::string m_type;
    std::size_t m_offset;
};

class ReflectionMethod
{
  public:
    ReflectionMethod(ReflectionMethod &&) = delete;

    /**
     * @brief 默认构造
     *
     */
    ReflectionMethod() = default;

    /**
     * @brief 标准构造
     *
     * @param[in] name
     * @param[in] method
     */
    ReflectionMethod(const std::string &name, uintptr_t method) : m_name(name), m_method(method)
    {
    }

    /**
     * @brief 方法名
     *
     * @return const std::string&
     */
    const std::string &name() const noexcept
    {
        return m_name;
    }

    /**
     * @brief 方法指针
     *
     * @return uintptr_t
     */
    uintptr_t method() const noexcept
    {
        return m_method;
    }

  private:
    std::string m_name;
    uintptr_t m_method;
};

class ReflectionFactory
{
    friend class Singleton<ReflectionFactory>;

  private:
    ReflectionFactory() = default;
    ~ReflectionFactory() = default;
    ReflectionFactory(ReflectionFactory &&) = delete;

  public:
    /**
     * @brief 注册类
     *
     * @param[in] className
     * @param[in] creator
     */
    void register_class(const std::string &className, create_object creator)
    {
        m_creators[className] = creator;
    }

    /**
     * @brief 创建类
     *
     * @param[in] className
     * @return ReflectionObject*
     */
    ReflectionObject *create_class(const std::string &className)
    {
        auto it = m_creators.find(className);
        if (it == m_creators.end())
            return nullptr;

        // 调用 create_object 指针指向的函数，返回创建的对象指针
        return it->second();
    }

    /**
     * @brief 注册类字段
     *
     * @param[in] className
     * @param[in] fieldName
     * @param[in] fieldType
     * @param[in] offset
     */
    void register_field(const std::string &className, const std::string &fieldName, const std::string &fieldType,
                        size_t offset)
    {
        m_fields[className].push_back(new ReflectionField(fieldName, fieldType, offset));
    }

    /**
     * @brief 获得类字段数量
     *
     * @param[in] className
     * @return std::size_t
     */
    std::size_t field_num(const std::string &className)
    {
        return m_fields[className].size();
    }

    /**
     * @brief 获得类字段
     *
     * @param[in] className
     * @param[in] index
     * @return ReflectionField*
     */
    ReflectionField *field(const std::string &className, std::size_t index)
    {
        std::size_t size = m_fields[className].size();
        if (index >= size)
            return nullptr;
        return m_fields[className][index];
    }

    /**
     * @brief 获得类字段
     *
     * @param[in] className
     * @param[in] fieldName
     * @return ReflectionField*
     */
    ReflectionField *field(const std::string &className, const std::string &fieldName)
    {
        for (auto field : m_fields[className])
        {
            if (field->name() == fieldName)
                return field;
        }
        return nullptr;
    }

    /**
     * @brief 注册类方法
     *
     * @param[in] className
     * @param[in] methodName
     * @param[in] method
     */
    void register_method(const std::string &className, const std::string &methodName, uintptr_t method)
    {
        m_methods[className].push_back(new ReflectionMethod(methodName, method));
    }

    /**
     * @brief 获得类方法数量
     *
     * @param[in] className
     * @return std::size_t
     */
    std::size_t method_num(const std::string &className)
    {
        return m_methods[className].size();
    }

    /**
     * @brief 获得类方法
     *
     * @param[in] className
     * @param[in] index
     * @return ReflectionMethod*
     */
    ReflectionMethod *method(const std::string &className, std::size_t index)
    {
        std::size_t size = m_methods[className].size();
        if (index >= size)
            return nullptr;
        return m_methods[className][index];
    }

    /**
     * @brief 获得类方法
     *
     * @param[in] className
     * @param[in] methodName
     * @return ReflectionMethod*
     */
    ReflectionMethod *method(const std::string &className, const std::string &methodName)
    {
        for (auto method : m_methods[className])
        {
            if (method->name() == methodName)
                return method;
        }
        return nullptr;
    }

  private:
    std::map<std::string, create_object> m_creators;
    std::map<std::string, std::vector<ReflectionField *>> m_fields;
    std::map<std::string, std::vector<ReflectionMethod *>> m_methods;
};

} // namespace details

using ReflectionFactory = Singleton<details::ReflectionFactory>;

class ReflectionObject
{
  public:
    ReflectionObject() = default;
    virtual ~ReflectionObject() = default;

    /**
     * @brief 获得类名
     *
     * @return const std::string&
     */
    const std::string &class_name() const noexcept
    {
        return m_className;
    }

    /**
     * @brief 设置类名
     *
     * @return std::string&
     */
    std::string &class_name() noexcept
    {
        return m_className;
    }

    /**
     * @brief 借助 ReflectionFactory 获得类信息
     *
     * @return std::size_t
     */
    std::size_t field_num() const noexcept
    {
        return ReflectionFactory::instance().field_num(m_className);
    }

    /**
     * @brief 获得类字段
     *
     * @param[in] index
     * @return ReflectionField*
     */
    details::ReflectionField *field(std::size_t index) const noexcept
    {
        return ReflectionFactory::instance().field(m_className, index);
    }

    /**
     * @brief 获得类字段
     *
     * @param[in] fieldName
     * @return ReflectionField*
     */
    details::ReflectionField *field(const std::string &fieldName) const noexcept
    {
        return ReflectionFactory::instance().field(m_className, fieldName);
    }

    /**
     * @brief 由于无法通过返回值类型匹配模板，只能通过参数传入 value
     *
     * @tparam T
     * @param[in] fieldName
     * @param[in] value
     */
    template <typename T> void value(const std::string &fieldName, T &value) const
    {
        details::ReflectionField *field = ReflectionFactory::instance().field(m_className, fieldName);
        if (field == nullptr)
            return;
        value = *(T *)((std::size_t)this + field->offset());
    }

    /**
     * @brief 由于无法通过返回值类型匹配模板，只能通过参数传入 value
     *
     * @tparam T
     * @param[in] fieldName
     * @param[in] value
     */
    template <typename T> void set_value(const std::string &fieldName, const T &value)
    {
        details::ReflectionField *field = ReflectionFactory::instance().field(m_className, fieldName);
        if (field == nullptr)
            return;
        *(T *)((std::size_t)this + field->offset()) = value;
    }

    /**
     * @brief 方法数
     *
     * @return std::size_t
     */
    std::size_t method_num() const noexcept
    {
        return ReflectionFactory::instance().method_num(m_className);
    }

    /**
     * @brief 获得类方法
     *
     * @param[in] index
     * @return ReflectionMethod*
     */
    details::ReflectionMethod *method(std::size_t index) const noexcept
    {
        return ReflectionFactory::instance().method(m_className, index);
    }

    /**
     * @brief 获得类方法
     *
     * @param[in] methodName
     * @return ReflectionMethod*
     */
    details::ReflectionMethod *method(const std::string &methodName) const noexcept
    {
        return ReflectionFactory::instance().method(m_className, methodName);
    }

    /**
     * @brief 使用变长参数模板调用类方法
     *
     * @tparam T
     * @tparam Args
     * @param[in] methodName
     * @param[in] args
     * @return T
     */
    template <typename T = void, typename... Args> T call(const std::string &methodName, Args... args)
    {
        details::ReflectionMethod *method = ReflectionFactory::instance().method(m_className, methodName);
        if (method == nullptr)
            return T{};

        // 借助 decltype(this) 获得 this 指针的类型
        return (*((std::function<T(decltype(this), Args...)> *)method->method()))(this, std::forward<Args>(args)...);
    }

  private:
    std::string m_className;
};

namespace details
{

// 注册器，利用 RAII 机制，自动注册类，自动销毁。注册器调用工厂的注册字段函数，不需要友元关系
class ReflectionRegister
{
  public:
    /**
     * @brief 注册构造函数
     *
     * @param[in] name
     * @param[in] creator
     */
    ReflectionRegister(const std::string &name, create_object creator)
    {
        Singleton<ReflectionFactory>::instance().register_class(name, creator);
    }

    /**
     * @brief 注册类字段
     *
     * @param[in] className
     * @param[in] fieldName
     * @param[in] fieldType
     * @param[in] offset
     */
    ReflectionRegister(const std::string &className, const std::string &fieldName, const std::string &fieldType,
                       size_t offset)
    {
        Singleton<ReflectionFactory>::instance().register_field(className, fieldName, fieldType, offset);
    }

    /**
     * @brief 注册类方法
     *
     * @param[in] className
     * @param[in] methodName
     * @param[in] method
     */
    ReflectionRegister(const std::string &className, const std::string &methodName, uintptr_t method)
    {
        Singleton<ReflectionFactory>::instance().register_method(className, methodName, method);
    }
};

} // namespace details

} // namespace utils

} // namespace xi

// 宏定义，简化注册过程
#define REGISTER_CLASS(className)                                                                                      \
    namespace xi                                                                                                       \
    {                                                                                                                  \
    namespace details                                                                                                  \
    {                                                                                                                  \
    inline xi::utils::ReflectionObject *_createObject##className()                                                     \
    {                                                                                                                  \
        xi::utils::ReflectionObject *p = new className;                                                                \
        p->class_name() = #className;                                                                                  \
        return p;                                                                                                      \
    }                                                                                                                  \
    inline xi::utils::details::ReflectionRegister _register##className(#className, _createObject##className);          \
    }                                                                                                                  \
    }

#define REGISTER_FIELD(className, fieldName, fieldType)                                                                \
    namespace xi                                                                                                       \
    {                                                                                                                  \
    namespace utils                                                                                                    \
    {                                                                                                                  \
    namespace details                                                                                                  \
    {                                                                                                                  \
    inline className _className##fieldName;                                                                            \
    inline xi::utils::details::ReflectionRegister _register##className##fieldName(                                     \
        #className, #fieldName, #fieldType,                                                                            \
        (std::size_t)&_className##fieldName.fieldName - (std::size_t)&_className##fieldName);                          \
    }                                                                                                                  \
    }                                                                                                                  \
    }

#define REGISTER_METHOD(className, methodName, returnType, ...)                                                        \
    namespace xi                                                                                                       \
    {                                                                                                                  \
    namespace utils                                                                                                    \
    {                                                                                                                  \
    namespace details                                                                                                  \
    {                                                                                                                  \
    inline std::function<returnType(className *, __VA_ARGS__)> _register##className##methodName##Func =                \
        &className::methodName;                                                                                        \
    inline xi::utils::details::ReflectionRegister _register##className##methodName(                                    \
        #className, #methodName, (uintptr_t)(&_register##className##methodName##Func));                                \
    }                                                                                                                  \
    }                                                                                                                  \
    }